home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / The World of Computer Software.iso / vim_src.zip / UNIX.C < prev    next >
C/C++ Source or Header  |  1993-01-12  |  13KB  |  739 lines

  1. /* vi:ts=4:sw=4
  2.  *
  3.  *
  4.  * VIM - Vi IMitation
  5.  *
  6.  * Code Contributions By:    Bram Moolenaar            mool@oce.nl
  7.  *                            Tim Thompson            twitch!tjt
  8.  *                            Tony Andrews            onecom!wldrdg!tony 
  9.  *                            G. R. (Fred) Walter        watmath!watcgl!grwalter 
  10.  */
  11. /*
  12.  * unix.c -- BSD and SYSV code
  13.  *
  14.  * A lot of this file was written by Juergen Weigert.
  15.  */
  16.  
  17. #include "vim.h"
  18. #include "globals.h"
  19. #include "param.h"
  20. #include "proto.h"
  21.  
  22. #include <fcntl.h>
  23. #include <time.h>
  24. #include <sys/ioctl.h>
  25. #include <sys/types.h>
  26. #include <signal.h>
  27.  
  28. #ifdef SYSV
  29. # include <poll.h>
  30. # include <termio.h>
  31. #else
  32. # include <sgtty.h>
  33. # include <sys/time.h>
  34. #endif
  35.  
  36.  
  37. static int    Read __ARGS((int, char *, long));
  38. static int    WaitForChar __ARGS((int));
  39. static int    RealWaitForChar __ARGS((int));
  40. #ifndef linux
  41. static void sig_winch __ARGS((void));
  42. #endif
  43.  
  44. static int do_resize = FALSE;
  45.  
  46. /*
  47.  * At this point TRUE and FALSE are defined as 1L and 0L, but we want 1 and 0.
  48.  */
  49. #undef TRUE
  50. #define TRUE 1
  51. #undef FALSE
  52. #define FALSE 0
  53.  
  54. /*
  55.  * the number of calls to Write is reduced by using the buffer "outbuf"
  56.  */
  57. #define BSIZE    2048
  58. static u_char    outbuf[BSIZE];
  59. static int        bpos = 0;
  60.  
  61. /*
  62.  * flushbuf(): flush the output buffer
  63.  */
  64.     void
  65. flushbuf()
  66. {
  67.     if (bpos != 0)
  68.         write(1, (char *)outbuf, (long)bpos);
  69.     bpos = 0;
  70. }
  71.  
  72. /*
  73.  * outchar(c): put a character into the output buffer. Flush it if it becomes full.
  74.  */
  75.     void
  76. outchar(c)
  77.     unsigned c;
  78. {
  79.     if (c == '\n')        /* turn LF into CR-LF (CRMOD does not seem to do this) */
  80.         outchar('\r');
  81.     outbuf[bpos] = c;
  82.     ++bpos;
  83.     if (bpos >= BSIZE)
  84.         flushbuf();
  85. }
  86.  
  87. /*
  88.  * GetChars(): low level input funcion.
  89.  * Get a characters from the keyboard.
  90.  * If type == T_PEEK do not wait for characters.
  91.  * If type == T_WAIT wait a short time for characters.
  92.  * If type == T_BLOCK wait for characters.
  93.  */
  94.     int
  95. GetChars(buf, maxlen, type)
  96.     char    *buf;
  97.     int        maxlen;
  98.     int        type;
  99. {
  100.     int        len;
  101.     int        time = 1000;
  102.  
  103.     switch (type)
  104.     {
  105.     case T_PEEK:
  106.         time = 20;
  107.     case T_WAIT:
  108.         if (WaitForChar(time) == 0)        /* no character available */
  109.             return 0;
  110.         break;
  111.  
  112.     case T_BLOCK:
  113.     /*
  114.      * If there is no character available within 2 seconds (default)
  115.      * write the autoscript file to disk
  116.      */
  117.         if (WaitForChar((int)p_ut) == 0)
  118.             updatescript(0);
  119.     }
  120.  
  121.     for (;;)    /* repeat until we got a character */
  122.     {
  123.         /* 
  124.          * we want to be interrupted by the winch signal
  125.          */
  126.         WaitForChar(-1);
  127.         if (do_resize)
  128.         {
  129.             debug("do_resize!\n");
  130.             set_winsize(0, 0, FALSE);
  131.             do_resize = FALSE;
  132.             continue;
  133.         }
  134.         len = Read(0, buf, (long)maxlen);
  135.         if (len > 0)
  136.             return len;
  137.     }
  138. }
  139.  
  140.     void
  141. vim_delay()
  142. {
  143. #ifdef SYSV
  144.     poll(0,0, 500);
  145. #else
  146.     struct timeval tv;
  147.  
  148.     tv.tv_sec = 25 / 50;
  149.     tv.tv_usec = (25 % 50) * (1000000/50);
  150.     select(0, 0, 0, 0, &tv);
  151. #endif
  152. }
  153.  
  154.     static void
  155. sig_winch()
  156. {
  157. #if defined(SYSV) || defined(linux)
  158.     signal(SIGWINCH, sig_winch);
  159. #endif
  160.     do_resize = TRUE;
  161. }
  162.  
  163. /*
  164.  * If the machine has job control, use it to suspend the program,
  165.  * otherwise fake it by starting a new shell.
  166.  */
  167.     void
  168. mch_suspend()
  169. {
  170. #ifdef SIGTSTP
  171.     settmode(0);
  172.     kill(0, SIGTSTP);        /* send ourselves a STOP signal */
  173.     settmode(1);
  174. #else
  175.     outstr("new shell started\n");
  176.     call_shell(NULL, 0);
  177. #endif
  178. }
  179.  
  180.     void
  181. mch_windinit()
  182. {
  183.     Columns = 80;
  184.     Rows = 24;
  185.  
  186.     flushbuf();
  187.  
  188.     mch_get_winsize();
  189.     signal(SIGWINCH, sig_winch);
  190. }
  191.  
  192. /*
  193.  * Check_win checks whether we have an interactive window.
  194.  * If not, a new window is opened with the newcli command.
  195.  * If we would open a window ourselves, the :sh and :! commands would not
  196.  * work properly (Why? probably because we are then running in a background CLI).
  197.  * This also is the best way to assure proper working in a next Workbench release.
  198.  *
  199.  * For the -e option (quickfix mode) we open our own window and disable :sh.
  200.  * Otherwise we would never know when editing is finished.
  201.  */
  202. #define BUF2SIZE 320        /* lenght of buffer for argument with complete path */
  203.  
  204.     void
  205. check_win(argc, argv)
  206.     int argc;
  207.     char **argv;
  208. {
  209.     if (!isatty(0) || !isatty(1))
  210.     {
  211.         fprintf(stderr, "VIM: no controlling terminal\n");
  212.         exit(2);
  213.     }
  214. }
  215.  
  216. /*
  217.  * fname_case(): Set the case of the filename, if it already exists.
  218.  *                 This will cause the filename to remain exactly the same.
  219.  */
  220.     void
  221. fname_case(name)
  222.     char *name;
  223. {
  224. }
  225.  
  226.     void
  227. settitle(str)
  228.     char *str;
  229. {
  230. }
  231.  
  232.     void
  233. resettitle()
  234. {
  235. }
  236.  
  237. /*
  238.  * get name of current directory into buffer 'buf' of length 'len' bytes
  239.  */
  240.     int 
  241. dirname(buf, len)
  242.     char *buf;
  243.     int len;
  244. {
  245. #ifdef SYSV
  246.     extern int        errno;
  247.     extern char        *sys_errlist[];
  248.  
  249.     if (getcwd(buf,len) == NULL)
  250.     {
  251.         strcpy(buf, sys_errlist[errno]);
  252.         return 1;
  253.     }
  254.     return 0;
  255. #else
  256.     return (int)getwd(buf);
  257. #endif
  258. }
  259.  
  260. /*
  261.  * get absolute filename into buffer 'buf' of length 'len' bytes
  262.  */
  263.     int 
  264. FullName(fname, buf, len)
  265.     char *fname, *buf;
  266.     int len;
  267. {
  268.     *buf = 0;
  269. #if defined(linux) || defined(UNIX_WITHOUT_AMD)
  270.     {
  271.         int l;
  272.  
  273.         if (*fname != '/')
  274.         {
  275. #ifdef SYSV
  276.             (void)getcwd(buf,len);
  277. #else
  278.             (void)getwd(buf);
  279. #endif
  280.             l = strlen(buf);
  281.             if (l && buf[l-1] != '/')
  282.                 strcat(buf, "/");
  283.         }
  284.     }
  285. #endif /* UNIX_WITHOUT_AMD */
  286.     strcat(buf, fname);
  287.     return 0;
  288. }
  289.  
  290. /*
  291.  * get file permissions for 'name'
  292.  */
  293.     long 
  294. getperm(name)
  295.     char *name;
  296. {
  297.     struct stat statb;
  298.  
  299.     if (stat(name, &statb))
  300.         return -1;
  301.     return statb.st_mode;
  302. }
  303.  
  304. /*
  305.  * set file permission for 'name' to 'perm'
  306.  */
  307.     int
  308. setperm(name, perm)
  309.     char *name;
  310.     int perm;
  311. {
  312.     return chmod(name, perm);
  313. }
  314.  
  315. /*
  316.  * check if "name" is a directory
  317.  */
  318.     int 
  319. isdir(name)
  320.     char *name;
  321. {
  322.     struct stat statb;
  323.  
  324.     if (stat(name, &statb))
  325.         return -1;
  326.     return (statb.st_mode & S_IFMT) != S_IFREG;
  327. }
  328.  
  329.     void
  330. mch_windexit(r)
  331.     int r;
  332. {
  333.     flushbuf();
  334.  
  335.     settmode(0);
  336.     stopscript();                    /* remove autoscript file */
  337.     exit(r);
  338. }
  339.  
  340.     void
  341. mch_settmode(raw)
  342.     int                raw;
  343. {
  344. #if defined(ECHOE) && defined(ICANON)
  345.     /* for "new" tty systems */
  346.     static struct termio told;
  347.            struct termio tnew;
  348.  
  349.     if (raw)
  350.     {
  351.         ioctl(0, TCGETA, &told);
  352.         tnew = told;
  353.         tnew.c_iflag &= ~ICRNL;            /* enables typing ^V^M */
  354.         tnew.c_lflag = ~(ICANON | ECHO | ISIG | ECHOE);
  355.         ioctl(0, TCSETA, &tnew);
  356.     }
  357.     else
  358.         ioctl(0, TCSETA, &told);
  359. #else
  360.     /* for "old" tty systems */
  361.     static struct sgttyb ttybold;
  362.            struct sgttyb ttybnew;
  363.  
  364.     if (raw)
  365.     {
  366.         ioctl(0, TIOCGETP, &ttybold);
  367.         ttybnew = ttybold;
  368.         ttybnew.sg_flags &= ~(CRMOD | ECHO);
  369.         ttybnew.sg_flags |= RAW;
  370.         ioctl(0, TIOCSETP, &ttybnew);
  371.     }
  372.     else
  373.         ioctl(0, TIOCSETP, &ttybold);
  374. #endif
  375. }
  376.  
  377.     int
  378. mch_get_winsize()
  379. {
  380.     int                old_Rows = Rows;
  381.     int                old_Columns = Columns;
  382.     char            *p;
  383.     struct winsize    ws;
  384.  
  385.     Columns = 0;
  386.     Rows = 0;
  387.     if (!do_resize)
  388.     {
  389.         if (p = getenv("LINES"))
  390.             Rows = atoi(p);
  391.         if (p = getenv("COLUMNS"))
  392.             Columns = atoi(p);
  393.         if (Columns <= 0 || Rows <= 0)
  394.             do_resize = TRUE;
  395.     }
  396.     if (do_resize)
  397.     {
  398. # ifdef TIOCGWINSZ
  399. #  ifdef DEBUG
  400.         extern int errno;
  401. #  endif /* DEBUG */
  402.  
  403.         if (ioctl(0, TIOCGWINSZ, &ws))
  404.         {
  405.             debug1("TIOCGWINSZ ioctl errno %d\n", errno);
  406.         }
  407.         else
  408.         {
  409.             Columns = ws.ws_col;
  410.             Rows = ws.ws_row;
  411.         }
  412. # endif /* TIOCGWINSZ */
  413.         do_resize = FALSE;
  414.     }
  415.     if (Columns <= 0 || Rows <= 0)
  416.     {
  417.         Columns = old_Columns;
  418.         Rows = old_Rows;
  419.         return 1;
  420.     }
  421.     debug2("mch_get_winsize: %dx%d\n", (int)Columns, (int)Rows);
  422.  
  423.     check_winsize();
  424.     script_winsize();
  425.  
  426. /* if size changed: screenalloc will allocate new screen buffers */
  427.     return (0);
  428. }
  429.  
  430.     void
  431. mch_set_winsize()
  432. {
  433.     /* should try to set the window size to Rows and Columns */
  434. }
  435.  
  436.     int 
  437. call_shell(cmd, dummy)
  438.     char    *cmd;
  439.     int        dummy;
  440. {
  441.     int        x;
  442.     char    newcmd[1024];
  443.  
  444.     flushbuf();
  445.  
  446.     settmode(0);                 /* set to cooked mode */
  447.  
  448.     if (cmd == NULL)
  449.         x = system(p_sh);
  450.     else
  451.     {            /* we use "sh" to start the shell, slow but easy */
  452.         sprintf(newcmd, "%s -c \"%s\"", p_sh, cmd);
  453.         x = system(newcmd);
  454.     }
  455.     if (x == 127)
  456.     {
  457.         smsg("Cannot execute shell sh");
  458.         outchar('\n');
  459.     }
  460.     else if (x)
  461.     {
  462.         smsg("%d returned", x);
  463.         outchar('\n');
  464.     }
  465.  
  466.     settmode(1);                         /* set to raw mode */
  467.     return x;
  468. }
  469.  
  470. /*
  471.  * The input characters are buffered to be able to check for a CTRL-C.
  472.  * This should be done with signals, but I don't know how to do that in
  473.  * a portable way for a tty in RAW mode.
  474.  */
  475.  
  476. #define INBUFLEN 50
  477. static char        inbuf[INBUFLEN];
  478. static int        inbufcount = 0;
  479.  
  480.     static int
  481. Read(fd, buf, maxlen)
  482.     int        fd;
  483.     char    *buf;
  484.     long    maxlen;
  485. {
  486.     if (inbufcount)        /* characters in inbuf[] */
  487.     {
  488.         if (maxlen > inbufcount)
  489.             maxlen = inbufcount;
  490.         memmove(buf, inbuf, maxlen);
  491.         inbufcount -= maxlen;
  492.         if (inbufcount)
  493.                 memmove(inbuf, inbuf + maxlen, inbufcount);
  494.         return (int)maxlen;
  495.     }
  496.     return read(fd, buf, maxlen);
  497. }
  498.  
  499.     void
  500. breakcheck()
  501. {
  502.     int len;
  503.  
  504. /*
  505.  * check for CTRL-C typed by reading all available characters
  506.  */
  507.     if (RealWaitForChar(0))        /* if characters available */
  508.     {
  509.         len = read(0, inbuf + inbufcount, (long)(INBUFLEN - inbufcount));
  510.         while (len-- > 0)
  511.         {
  512.             /*
  513.              * if a CTRL-C was typed, remove it from the buffer and set got_int
  514.              */
  515.             if (inbuf[inbufcount++] == 3)
  516.             {
  517.                 /* remove everything typed before the CTRL-C */
  518.                 if (len)
  519.                     memmove(inbuf, inbuf + inbufcount, len);
  520.                 inbufcount = 0;
  521.                 got_int = TRUE;
  522.                 flush_buffers();        /* remove all typeahead */
  523.             }
  524.         }
  525.     }
  526. }
  527.  
  528. /* 
  529.  * Wait "ticks" until a character is available from the keyboard or from inbuf[]
  530.  * ticks = -1 will block forever
  531.  */
  532.  
  533.     static int
  534. WaitForChar(ticks)
  535.     int ticks;
  536. {
  537.     if (inbufcount)        /* something in inbuf[] */
  538.         return 1;
  539.     return RealWaitForChar(ticks);
  540. }
  541.  
  542. /* 
  543.  * Wait "ticks" until a character is available from the keyboard
  544.  * ticks = -1 will block forever
  545.  */
  546.     static int
  547. RealWaitForChar(ticks)
  548.     int ticks;
  549. {
  550. #ifdef SYSV
  551.     struct pollfd fds;
  552.  
  553.     fds.fd = 0;
  554.     fds.events = POLLIN;
  555.     return (poll(&fds, 1, ticks));
  556. #else
  557.     struct timeval tv;
  558.     fd_set fdset;
  559.  
  560.     if (ticks >= 0)
  561.     {
  562.            tv.tv_sec = ticks / 1000;
  563.         tv.tv_usec = (ticks % 1000) * (1000000/1000);
  564.     }
  565.  
  566.     FD_ZERO(&fdset);
  567.     FD_SET(0, &fdset);
  568.     return (select(1, &fdset, 0, 0, (ticks >= 0) ? &tv : 0));
  569. #endif
  570. }
  571.  
  572.     int 
  573. remove(buf)
  574. #ifdef linux
  575.     const
  576. #endif
  577.             char *buf;
  578. {
  579.     return unlink(buf);
  580. }
  581.  
  582. #ifdef WILD_CARDS
  583. /*
  584.  * ExpandWildCard() - this code does wild-card pattern matching using the shell
  585.  *
  586.  * Mool: return 0 for success, 1 for error (you may loose some memory) and
  587.  *       put an error message in *file.
  588.  *
  589.  * num_pat is number of input patterns
  590.  * pat is array of pointers to input patterns
  591.  * num_file is pointer to number of matched file names
  592.  * file is pointer to array of pointers to matched file names
  593.  * On Unix we do not check for files only yet
  594.  * list_notfound is ignored
  595.  */
  596.  
  597. extern char *mktemp __ARGS((char *));
  598. #ifndef SEEK_SET
  599. # define SEEK_SET 0
  600. #endif
  601. #ifndef SEEK_END
  602. # define SEEK_END 2
  603. #endif
  604.  
  605.     int
  606. ExpandWildCards(num_pat, pat, num_file, file, files_only, list_notfound)
  607.     int             num_pat;
  608.     char          **pat;
  609.     int            *num_file;
  610.     char         ***file;
  611.     int                files_only;
  612.     int                list_notfound;
  613. {
  614.     char    tmpname[TMPNAMELEN];
  615.     char    *command;
  616.     int        i;
  617.     size_t    len;
  618.     FILE    *fd;
  619.     char    *buffer;
  620.     char    *p;
  621.  
  622.     *num_file = 0;        /* default: no files found */
  623.     *file = (char **)"";
  624.  
  625. /*
  626.  * get a name for the temp file
  627.  */
  628.     strcpy(tmpname, TMPNAME2);
  629.     if (*mktemp(tmpname) == NUL)
  630.     {
  631.         *file = (char **)e_notmp;
  632.         return 1;
  633.     }
  634.  
  635. /*
  636.  * let the shell expand the patterns and write the result into the temp file
  637.  */
  638.     len = TMPNAMELEN + 10;
  639.     for (i = 0; i < num_pat; ++i)        /* count the length of the patterns */
  640.         len += strlen(pat[i]) + 3;
  641.     command = (char *)alloc(len);
  642.     if (command == NULL)
  643.         return 1;
  644.     strcpy(command, "echo > ");            /* built the shell command */
  645.     strcat(command, tmpname);
  646.     for (i = 0; i < num_pat; ++i)
  647.     {
  648.         strcat(command, " \"");
  649.         strcat(command, pat[i]);
  650.         strcat(command, "\"");
  651.     }
  652.     i = call_shell(command, 0);                /* execute it */
  653.     free(command);
  654.     if (i)                                    /* call_shell failed */
  655.     {
  656.         remove(tmpname);
  657.         sleep(1);            /* give the user a chance to read error messages */
  658.         updateScreen(CLEAR);            /* probably messed up screen */
  659.         return 1;
  660.     }
  661.  
  662. /*
  663.  * read the names from the file into memory
  664.  */
  665.      fd = fopen(tmpname, "r");
  666.     if (fd == NULL)
  667.     {
  668.         *file = (char **)e_notopen;
  669.         return 1;
  670.     }
  671.     fseek(fd, 0L, SEEK_END);
  672.     len = ftell(fd);                /* get size of temp file */
  673.     fseek(fd, 0L, SEEK_SET);
  674.     buffer = (char *)alloc(len + 1);
  675.     if (buffer == NULL)
  676.     {
  677.         remove(tmpname);
  678.         fclose(fd);
  679.         return 1;
  680.     }
  681.     i = fread(buffer, 1, len, fd);
  682.     fclose(fd);
  683.     remove(tmpname);
  684.     if (i != len)
  685.     {
  686.         *file = (char **)e_notread;
  687.         free(buffer);
  688.         return 1;
  689.     }
  690.  
  691.     p = buffer;
  692.     for (i = 0; *p; ++i)        /* get number of entries */
  693.     {
  694.         while (*p != ' ' && *p != '\n')
  695.             ++p;
  696.         if (*p == '\n')
  697.         {
  698.             ++i;
  699.             break;
  700.         }
  701.         skipspace(&p);
  702.     }
  703.     *num_file = i;
  704.     *file = (char **)alloc(sizeof(char *) * i);
  705.     if (*file == NULL)
  706.     {
  707.         free(buffer);
  708.         *file = (char **)"";
  709.         return 1;
  710.     }
  711.     p = buffer;
  712.     for (i = 0; i < *num_file; ++i)
  713.     {
  714.         (*file)[i] = p;
  715.         while (*p != ' ' && *p != '\n')
  716.             ++p;
  717.         if (*p == '\n')
  718.         {
  719.             *p = NUL;
  720.             break;
  721.         }
  722.         *p++ = NUL;
  723.         skipspace(&p);
  724.     }
  725.     return 0;
  726. }
  727.  
  728.     void
  729. FreeWild(num, file)
  730.     int        num;
  731.     char    **file;
  732. {
  733.     if (file == NULL || num <= 0)
  734.         return;
  735.     free(file[0]);
  736.     free(file);
  737. }
  738. #endif    /* WILD_CARDS */
  739.